/**
 *  @file HttpUtility.cpp
 */
#include "HttpUtility.h"
#include "../../../convert/Convert.h"
#include "../../../util/DateTime.h"
#include "../../../util/DateTimeEnum.h"
#include "../../../lang/enumT.h"
#include "../../../common/ObjPtrT.h"

using namespace cppflib::collections;
using namespace cppflib::util;
using namespace cppflib::lang;

namespace cppflib
{

namespace net
{

namespace http
{

namespace util
{

/**
 *  Convert a name-value list to URL encoded string
 *
 *  @param [in] keyValueParameters -- the key value list
 *  @param [out] ret -- resultant URL encoded string
 */
_DLLAPI void UrlEncodeNameValuePairs(const NameValueList &keyValueParameters, CFString &ret)
{
   CFString name, val;
   for (int i = 0; i < static_cast<int>(keyValueParameters.GetCount()); ++i) {
      convert::ToUrlEncodedString(*keyValueParameters.GetKey(i), name);
      convert::ToUrlEncodedString(*keyValueParameters.GetVal(i), val);
      ret.AppendFormat(_S("%s=%s&"), static_cast<pcwstr_t>(name), static_cast<pcwstr_t>(val));
   }
   ret.Delete(ret.GetLength() - 1, 1); // remove the last "&"
}

/**
 *  Decode url encoded name-value string
 *
 *  @param [in] nameValStr -- the source url encoded string, e.g. xxx1=yyy1&xxx2=yyy2&xxx3=yyy3
 *  @param [out] retKVList -- resultant name-value list
 */
_DLLAPI void DecodeUrlEncodedNameValueString(const CFString &nameValStr, collections::NameValueList &retKVList)
{
   int sStart = 0, index = 0;

   while(true) {
      // find name end
      index = sStart;
      while (index < nameValStr.GetLength()) {
         if (nameValStr[index] == _S('='))
            break;
         ++index;
      }

      if (index >= nameValStr.GetLength())
         break;

      // retrieve name part
      CFString *pName = new CFString();
      convert::DecodeUrlEncodedString(nameValStr, sStart, index - sStart, *pName);

      // find value end
      ++index;
      sStart = index;
      while (index < nameValStr.GetLength()) {
         if (nameValStr[index] == _S('&'))
            break;
         ++index;
      }

      if (index == sStart)
         break;

      // retrieved value part
      CFString *pVal = new CFString();
      convert::DecodeUrlEncodedString(nameValStr, sStart, index - sStart, *pVal);

      retKVList.AddTail(pName, pVal);

      // update
      ++index;
      sStart = index;
   }
}


/** 
 *  Get current date time in RFC1123 format, 
 *  i.e.   Sun, 06 Nov 1994 08:49:37 GMT
 */
_DLLAPI void GetRfc1123DateFormat(CFString &date)
{
   ObjPtrT<DateTime> pUtcDate(DateTime::UtcNow());
   CFString dayOfWeek(Enum::GetString<dayofweek_t>(pUtcDate->DayOfWeek()));
   CFString month(Enum::GetString<month_t>(static_cast<month_t>(pUtcDate->Month())));

   dayOfWeek.Delete(3, dayOfWeek.GetLength() - 3);
   month.Delete(3, month.GetLength() - 3);

   date.Format(_S("%s, %02d %s %d %02d:%02d:%02d GMT"), static_cast<pcwstr_t>(dayOfWeek), pUtcDate->Day(),
                                                        static_cast<pcwstr_t>(month), pUtcDate->Year(),
                                                        pUtcDate->Hour(), pUtcDate->Min(), pUtcDate->Sec());
}


} // end of namespace util

} // end of namespace http

} // end of namespace net

} // end of namespace cppflib
